package View;

import Model.ImageModel;
import Model.ImageModelEvent;
import Model.ImageModelListener;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.URL;

import Controller.Controller;
import Settings.Settings;


public class MainFrame extends JFrame implements ImageModelListener {
    private Controller controller;
    private ImagePanel myImagePanel;
    private ImageModel imageModel;
    public static final String SAVE_COMMAND = "Save";
    public static final String SAVE_AS_COMMAND = "SaveAs";
    public static final String OPEN_COMMAND = "Open";
    public static final String EXIT_COMMAND = "Exit";
    public static final String EROSION_COMMAND = "Erosion";
    public static final String DILATATION_COMMAND = "Dilatation";
    public static final String INVERSION_COMMAND = "Inversion";
    public static final String WB_COMMAND = "WB";
    public static final String LINFILTER_COMMAND = "LinFilter";
    public static final String WHITENOISE_COMMAND = "WhiteNoise";
    public static final String DUST_COMMAND = "Dust";
    public static final String UNDO_COMMAND = "Undo";
    public static final String REDO_COMMAND = "Redo";
    public static final String GRID_COMMAND = "Grid";
    public static final String COMPARE_COMMAND = "Compare";
    public static final String GOLDENIMAGE_COMMAND = "Golden image";
    public static final String DIFF_COMMAND = "Difference";
    public static final String MEDIAN_COMMAND = "Median";
    public static final String MOTION_BLUR = "Motion blur";
    public static final String ZOOM_BLUR = "Zoom blur";
    public static final String SPIN_BLUR = "Spin blur";
    public static final String LOG_COMMAND = "LoG";
    public static final String K_MEANS = "k-means";
    public static final String MEANSHIFT = "MEANSHIFT";
    public static final String SALT_PEPPER = "Salt_Pepper";
    private boolean isRedoEnabled;
    private boolean isUndoEnabled;

    private JMenuBar jmb = new JMenuBar();
    private JMenu jmFile = new JMenu("File");
    private JMenuItem jmiSaveAs = new JMenuItem("Save as...");
    private JMenuItem jmiOpen = new JMenuItem("Open");
    private JMenuItem jmiSave = new JMenuItem("Save");
    private JMenuItem jmiExit = new JMenuItem("Exit");
    private JMenu jmFilters = new JMenu("Filters");
    private JMenuItem jmiErosion = new JMenuItem("Erosion");
    private JMenuItem jmiDilatation = new JMenuItem("Dilatation");
    private JMenuItem jmiInversion = new JMenuItem("Inversion");
    private JMenuItem jmiWB = new JMenuItem("WB");
    private JMenuItem jmiLinearFilter = new JMenuItem("LinearFilter");
    private JMenuItem jmiWhiteNoise = new JMenuItem("White Noise");
    private JMenuItem jmiDust = new JMenuItem("Dust");
    private JMenuItem jmiMedian = new JMenuItem("Median");
    private JMenuItem jmiMotionBlur = new JMenuItem("Motion blur");
    private JMenuItem jmiZoomBlur = new JMenuItem("Zoom blur");
    private JMenuItem jmiSpinBlur = new JMenuItem("Spin blur");
    private JMenuItem jmiLoG = new JMenuItem("LoG");
    private JMenuItem jmiKMeans = new JMenuItem("k-means clusterization");
    private JMenuItem jmiMeanShift = new JMenuItem("Mean Shift");
    private JMenuItem jmiSaltPepper = new JMenuItem("Salt and Pepper noise");
    private JMenu jmAddFilters = new JMenu("Additional Filters");


    private JMenu jmHistory = new JMenu("History");
    private JMenuItem jmiUndo = new JMenuItem("Undo");
    private JMenuItem jmiRedo = new JMenuItem("Redo");
    private JMenuItem jmiUserFilter = new JMenuItem("User Filter");
    private JMenu jmTools = new JMenu("Tools");
    private JMenuItem jmiGrid = new JMenuItem("Grid");
    private JMenuItem jmiCompare = new JMenuItem("Compare");
    private JMenuItem jmiGoldenImageFolder = new JMenuItem("Set golden image folder");
    private JMenuItem jmiDiffFolder = new JMenuItem("Set difference folder");
    private JToolBar toolBar = new JToolBar();
    private JMenu jmSettings = new JMenu("Settings");
    private JButton jbUndo;
    private JButton jbRedo;
    private JButton jbGrid;
    private JButton jbCompare;
    private JButton jbMedian;

    public ImagePanel getMyImagePanel() {
        return myImagePanel;
    }

    public ImageModel getImageModel() {
        return imageModel;
    }

    public MainFrame(ImageModel model) {
        setTitle("Cute Picture Viewer");
        setSize();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


        jmiSaveAs.setEnabled(false);
        jmiSave.setEnabled(false);
        jmiOpen.setActionCommand(OPEN_COMMAND);
        jmiSave.setActionCommand(SAVE_COMMAND);
        jmiSaveAs.setActionCommand(SAVE_AS_COMMAND);
        jmiExit.setActionCommand(EXIT_COMMAND);

        imageModel = model;

        controller = new Controller(this, model);
        jmiOpen.addActionListener(controller);
        jmiSave.addActionListener(controller);
        jmiSaveAs.addActionListener(controller);
        jmiExit.addActionListener(controller);
        jmFile.add(jmiOpen);
        jmFile.add(jmiSave);
        jmFile.add(jmiSaveAs);
        jmFile.addSeparator();
        jmFile.add(jmiExit);
        jmb.add(jmFile);

        jmiErosion.setActionCommand(EROSION_COMMAND);
        jmiErosion.addActionListener(controller);
        jmFilters.add(jmiErosion);

        jmiDilatation.setActionCommand(DILATATION_COMMAND);
        jmiDilatation.addActionListener(controller);
        jmFilters.add(jmiDilatation);

        jmiInversion.setActionCommand(INVERSION_COMMAND);
        jmiInversion.addActionListener(controller);
        jmFilters.add(jmiInversion);

        jmiWB.setActionCommand(WB_COMMAND);
        jmiWB.addActionListener(controller);
        jmFilters.add(jmiWB);


        jmiLinearFilter.setActionCommand(LINFILTER_COMMAND);
        jmiLinearFilter.addActionListener(controller);
        jmFilters.add(jmiLinearFilter);

        jmiWhiteNoise.setActionCommand(WHITENOISE_COMMAND);
        jmiWhiteNoise.addActionListener(controller);
        jmFilters.add(jmiWhiteNoise);

        jmiDust.setActionCommand(DUST_COMMAND);
        jmiDust.addActionListener(controller);
        jmFilters.add(jmiDust);

        jmiMedian.setActionCommand(MEDIAN_COMMAND);
        jmiMedian.addActionListener(controller);
        jmFilters.add(jmiMedian);

        jmiMotionBlur.setActionCommand(MOTION_BLUR);
        jmiMotionBlur.addActionListener(controller);
        jmAddFilters.add(jmiMotionBlur);

        jmiZoomBlur.setActionCommand(ZOOM_BLUR);
        jmiZoomBlur.addActionListener(controller);
        jmAddFilters.add(jmiZoomBlur);

        jmiSpinBlur.setActionCommand(SPIN_BLUR);
        jmiSpinBlur.addActionListener(controller);
        jmAddFilters.add(jmiSpinBlur);

        jmiLoG.setActionCommand(LOG_COMMAND);
        jmiLoG.addActionListener(controller);
        jmAddFilters.add(jmiLoG);

        jmiKMeans.setActionCommand(K_MEANS);
        jmiKMeans.addActionListener(controller);
        jmAddFilters.add(jmiKMeans);

        jmiMeanShift.setActionCommand(MEANSHIFT);
        jmiMeanShift.addActionListener(controller);
        jmAddFilters.add(jmiMeanShift);

        jmiSaltPepper.setActionCommand(SALT_PEPPER);
        jmiSaltPepper.addActionListener(controller);
        jmAddFilters.add(jmiSaltPepper);


        jmFilters.setEnabled(false);
        jmb.add(jmFilters);

        jmAddFilters.setEnabled(false);
        jmb.add(jmAddFilters);


        jmiUndo.setActionCommand(UNDO_COMMAND);
        jmiUndo.addActionListener(controller);
        jmiRedo.setActionCommand(REDO_COMMAND);
        jmiRedo.addActionListener(controller);
        jmHistory.add(jmiUndo);
        jmHistory.add(jmiRedo);
        jmb.add(jmHistory);
        jmiUndo.setEnabled(false);
        jmiRedo.setEnabled(false);
        jmHistory.setEnabled(false);

        jmiDiffFolder.setActionCommand(DIFF_COMMAND);
        jmiDiffFolder.addActionListener(controller);
        jmiGoldenImageFolder.setActionCommand(GOLDENIMAGE_COMMAND);
        jmiGoldenImageFolder.addActionListener(controller);
        jmiGrid.setActionCommand(GRID_COMMAND);
        jmiGrid.addActionListener(controller);
        jmiCompare.setActionCommand(COMPARE_COMMAND);
        jmiCompare.addActionListener(controller);
        jmTools.add(jmiGrid);
        jmTools.add(jmiCompare);
        jmSettings.add(jmiGoldenImageFolder);
        jmSettings.add(jmiDiffFolder);
        jmb.add(jmTools);
        jmb.add(jmSettings);
        jmTools.setEnabled(false);


        myImagePanel = new ImagePanel();
        myImagePanel.setImage(imageModel.getImage());
        myImagePanel.setBackground(Color.WHITE);


        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        WindowListener windowListener = new WindowAdapter() {
            public void windowClosing(WindowEvent w) {
                imageModel.saveSettings();
                Settings.getInstance().save();
                controller.disposeDialogs();
                MainFrame.this.setVisible(false);
                MainFrame.this.dispose();
            }
        };
        this.addWindowListener(windowListener);

        setLayout(new BorderLayout());

        jbUndo = createButton("Undo.png", UNDO_COMMAND, "Undo", "Undo");
        toolBar.add(jbUndo);
        jbUndo.setEnabled(false);
        jbRedo = createButton("Redo.png", REDO_COMMAND, "Redo", "Redo");
        toolBar.add(jbRedo);
        jbRedo.setEnabled(false);
        jbGrid = createButton("grid.png", GRID_COMMAND, "Grid", "Grid");
        toolBar.add(jbGrid);
        jbGrid.setEnabled(false);

        jbCompare = createButton("Compare.png", COMPARE_COMMAND, "Compare", "Compare");
        toolBar.add(jbCompare);
        jbCompare.setEnabled(false);

        jbMedian = createButton("Median.png", MEDIAN_COMMAND, "Median", "Median");
        toolBar.add(jbMedian);
        jbMedian.setEnabled(false);

        toolBar.setPreferredSize(new Dimension(this.getWidth(), 30));
        toolBar.setFloatable(false);
        toolBar.setRollover(true);
        toolBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.GRAY));

        //myImagePanel.setBorder(BorderFactory.createMatteBorder(0, 2, 0, 2, Color.GRAY));

        this.add(myImagePanel, BorderLayout.CENTER);
        this.add(toolBar, BorderLayout.PAGE_START);
        setJMenuBar(jmb);
        setVisible(true);
    }

    private void setSize() {
        int width = 700;
        int height = 500;
        Dimension dim = null;
        try {
            dim = Toolkit.getDefaultToolkit().getScreenSize();
        } catch (HeadlessException e) {
            System.err.println("Couldn't get screensize");
        }

        if (dim != null) {
            dim.setSize(dim.getWidth() - 100, dim.getHeight() - 100);
            setSize(dim);
        } else {
            setSize(new Dimension(width, height));
        }
        setLocation(50, 50);
        setMinimumSize(new Dimension(200, 200));
    }

    public void disableButtons() {
        for (Component c : getComponents()) {
            c.setEnabled(false);
        }
    }

    public void imageChanged(ImageModelEvent e) {
        String message = e.getMessage();
        if (message.equals(ImageModel.IMAGE_NOT_OPENED)) {
            JOptionPane.showMessageDialog(this, "Couldn't open file " + e.getAdditMessage());
        } else {
            if (message.equals(ImageModel.IMAGE_NOT_SAVED)) {
                JOptionPane.showMessageDialog(this, "Couldn't save file " + e.getAdditMessage());
            } else if (message.equals(ImageModel.IMAGE_CHANGED)) {

                myImagePanel.setImage(e.getImageModel().getImage());
                isRedoEnabled = false;
                isUndoEnabled = false;
                if (!e.getImageModel().isCurrentIndexFirst()) {
                    isUndoEnabled = true;
                }
                if (!e.getImageModel().isCurrentIndexLast()) {
                    isRedoEnabled = true;
                }
                setDefaults();
                repaint();
            }
        }
    }

    public void setDefaults() {
        setTitle("Cute Picture Viewer - " + imageModel.getShortFileName());
        jmiSave.setEnabled(true);
        jmiSaveAs.setEnabled(true);
        jmFilters.setEnabled(true);
        jmAddFilters.setEnabled(true);
        jmTools.setEnabled(true);
        jbCompare.setEnabled(true);
        jbGrid.setEnabled(true);
        jbMedian.setEnabled(true);
        jmHistory.setEnabled(isRedoEnabled || isUndoEnabled);
        jmiUndo.setEnabled(isUndoEnabled);
        jbUndo.setEnabled(isUndoEnabled);
        jmiRedo.setEnabled(isRedoEnabled);
        jbRedo.setEnabled(isRedoEnabled);


    }

    protected JButton createButton(String imageName, String actionCommand, String toolTipText, String altText) {
        //Look for the image.
        String imgLocation = "/Resources/" + imageName;
        URL imageURL = this.getClass().getResource(imgLocation);

        //Create and initialize the button.
        JButton button = new JButton();
        button.setActionCommand(actionCommand);
        button.setToolTipText(toolTipText);
        button.addActionListener(controller);

        if (imageURL != null) { //image found
            ImageIcon imageIcon = new ImageIcon(imageURL, altText);
            button.setIcon(imageIcon);
        } else { //no image found
            button.setText(altText);
            System.err.println("Resource not found: " + imgLocation);
        }

        return button;
    }

    public void closeWindow() {

        MainFrame.this.processWindowEvent(new WindowEvent(MainFrame.this, WindowEvent.WINDOW_CLOSING));
    }

}